''' 卫星轨道模型
根据卫星轨道节点，生成对应的卫星轨道模型。
整个卫星轨道模型封装成一个单独类。
'''

from time import time
import numpy as np
import util

def ReconstructionSatelliteOrbit(GPSPoints_list,starttime=1262275200.0):
    '''
    构建卫星轨道
    args:
        GPSPoints_list:卫星轨道点
        starttime:起算时间，默认设置为2010年1月1日，0时0分0秒 
    '''
    if len(GPSPoints_list)>16:
        SatelliteOrbitModel=SatelliteOrbit_FitPoly()
        if SatelliteOrbitModel.ReconstructionSatelliteOrbit(GPSPoints_list,starttime=starttime) is None:
            return None
        return SatelliteOrbitModel

class SatelliteOrbit(object):
    def __init__(self) -> None:
        super().__init__()
        self.__starttime=1262275200.0

    pass
    def get_starttime(self):
        '''
        返回卫星轨道时间起算点
        '''
        return self.__starttime
    def ReconstructionSatelliteOrbit(self,GPSPoints_list):
        '''
        重建卫星轨道，使用多项式拟合法。
        args:
            GPSPoints_list:GPS卫星轨道点。
        return：
            SatelliteOrbitModel 卫星轨道模型
        '''
        self.SatelliteOrbitModel=None
        pass
    
    pass
    def SatelliteSpaceState(self,time_float):
        '''
        根据时间戳，返回对应时间的卫星的轨迹状态
        args:
            time_float:时间戳
        return：
            State_list:[time,Xp,Yp,Zp,Vx,Vy,Vz]
        '''
        return None
    
class SatelliteOrbit_FitPoly(SatelliteOrbit):
    '''
    继承于SatelliteOribit类，为拟合多项式实现方法
    '''
    def __init__(self) -> None:
        super().__init__()

    def ReconstructionSatelliteOrbit(self,GPSPoints_list,starttime=1262275200.0):
        if len(GPSPoints_list)>16: 
            # 多项式的节点数，理论上是超过4个可以起算，这里为了精度选择16个点起算。
            # 多项式 AX=Y ==> A=（X'X)^X'Y，其中 A 为待求系数，X为变量，Y为因变量
            # 这里使用三次项多项式，共有6组参数。
            # 声明自变量，因变量，系数矩阵
            self.__starttime=starttime
            record_count=len(GPSPoints_list)
            time_arr=np.zeros((record_count,1),dtype=np.float64) # 使用np.float64只是为了精度高些，如果32位也能满足需求，请用32
            state_arr=np.zeros((record_count,6),dtype=np.float64)
            A_arr=np.zeros((4,6),dtype=np.float64)
            # 将点记录转换为自变量矩阵、因变量矩阵
            for i in range(record_count):
                GPSPoint=GPSPoints_list[i]
                time_arr[i,0]=GPSPoint[0]-self.__starttime
                state_arr[i,:]=np.array(GPSPoint[1:]).reshape(1,6)
            # 使用最小二乘法，求解系数
            X=np.concatenate([np.ones((record_count,1),dtype=np.float64),time_arr,time_arr**2,time_arr**3],axis=1)
            
            for i in range(6):
                Y=state_arr[:,i]
                A_arr[:,i]=np.matmul(np.matmul(np.linalg.inv(np.matmul(X.T,X)),X.T),Y).reshape(1,4) # 
            self.A_arr=A_arr
            
            return A_arr
        else:
            self.A_arr=None
            return None
    def SatelliteSpaceState(self,time_float):
        '''
        根据时间戳，返回对应时间的卫星的轨迹状态，会自动计算与起算时间之差
        args:
            time_float:时间戳
        return：
            State_list:[time,Xp,Yp,Zp,Vx,Vy,Vz]
        '''
        if self.A_arr is None:
            return None
        time_float=time_float-self.__starttime
        time_arr=np.ones((1,4),dtype=np.float)
        time_arr[0,0]=time_arr[0,0]
        time_arr[0,1]=time_arr[0,1]*time_float
        time_arr[0,2]=time_arr[0,2]*time_float**2
        time_arr[0,3]=time_arr[0,3]*time_float**3
        SatelliteState_xyz_Vxyz_arr=np.matmul(time_arr,self.A_arr).reshape(1,6)
        return np.concatenate([np.array(time_float+self.__starttime).reshape(1,1),SatelliteState_xyz_Vxyz_arr],axis=1)




